#include "reg51.h"
#include "misc.h"
#include "ds18b20.h"
#include <INTRINS.H>

union {
    unsigned char c[2];
    unsigned int x;

} temp;

uchar idata flag = 0;
uint idata cc = 0;
uchar idata disp[8];

void delaynus(uchar i)
{
    while (--i)
        _nop_();
}
/****************************************************************
*函数功能：复位DS18B20
*入口参数：无
*出口参数：presence，指示复位是否成功
****************************************************************/
uchar Reset_DS18B20(void)
{
    uchar presence;
    DQ = 0;            //pull DQ line low
    delaynus(248);     // leave it low for 500us
    DQ = 1;            // allow line to return high
    delaynus(48);      // wait for presence 100us
    presence = DQ;     // get presence signal
    delaynus(198);     // wait for end of timeslot 400us
    return (presence); // presence signal returned
} // 0=presence, 1 = no part

/****************************************************************
*函数功能：读取DS18B20的一个字节
*入口参数：无
*出口参数：value，读取的一个字节
****************************************************************/
uchar read_byte(void)
{
    uchar i;
    uchar value = 0;
    for (i = 8; i > 0; i--)
    {
        value >>= 1;
        DQ = 0;      // pull DQ low to start timeslot
        DQ = 1;      // then return high
        delaynus(3); // 11us
        if (DQ)
            value |= 0x80;
        delaynus(25); // wait for rest of timeslot 55us
    }
    return (value);
}

/****************************************************************
*函数功能：写一个字节到DS18B20
*入口参数：val，要写的一个字节
*出口参数：无
****************************************************************/
void write_byte(uchar val)
{
    uchar i;
    for (i = 8; i > 0; i--)
    {
        DQ = 0;          // pull DQ low to start timeslot
        DQ = val & 0x01; // 写1时，使得15us以内拉高 整个写1时隙不低于60us,写0时保持低在60us到120us之间
        delaynus(38);    // hold value for remainder of timeslot 80us
        DQ = 1;
        val = val / 2;
    }
    delaynus(38); //80us
}
/****************************************************************
*函数功能：读取DS18B20的温度值
*入口参数：无
*出口参数：temp.x温度值
****************************************************************/
uint Read_Temperature(void)
{
    EA = 0;
    Reset_DS18B20();
    write_byte(0xCC); // Skip ROM
    write_byte(0xBE); // Read Scratch Pad
    temp.c[1] = read_byte();
    temp.c[0] = read_byte();
    Reset_DS18B20();
    write_byte(0xCC); //Skip ROM
    write_byte(0x44); // Start Conversion
    EA = 1;
    return temp.x;
}
/****************************************************************
*函数功能：将DS18B20的温度值送LCD显示
*入口参数：无
*出口参数：无
****************************************************************/
int DS18B20Disp()
{
    int ret = cc;
    flag = 0; //温度正负标志位
    cc = Read_Temperature();
    if (cc > 0xf800)
    {
        flag = 1;

        cc = ~cc + 1;
    }
    cc = cc * 0.625;

    ret = cc;
    if (flag)
        ret = -ret;
    return ret;
}
